﻿using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Xml;
using System.IO;
using System.Reflection;
using System.Text.Unicode;
using Tnelab.Common;

namespace Tnelab.Miniblink
{
    internal static class MBVip
    {
        /// <summary>
        /// 把node.dll展开到程序当前目录
        /// </summary>
        static MBVip()
        {
            var isX64 = IntPtr.Size == 8;
            var mbPath = @"runtimes\win-x86\native\mb.dll";
            var mbNodePath = @"runtimes\win-x86\native\miniblink_x64.dll";
            var nodePath = @"runtimes\win-x86\native\node.dll";
            if (isX64)
            {
                mbPath = @"runtimes\win-x64\native\mb.dll";
                mbNodePath = @"runtimes\win-x64\native\miniblink_x64.dll";
                nodePath = @"runtimes\win-x64\native\node.dll";
                if (!File.Exists(mbPath))
                {
                    mbPath = "mb.dll";
                    mbNodePath = "miniblink_x64.dll";
                    nodePath = "node.dll";
                }
                if (File.Exists(nodePath))
                {
                    File.Move(nodePath, mbNodePath,true);
                }
                nodePath = mbNodePath;
            }
            if (mbPath.StartsWith(@"runtimes\"))
            {
                Win32Api.LoadLibraryW(nodePath);
                Win32Api.LoadLibraryW(mbPath);
            }

            var settingsPtr = Marshal.AllocHGlobal(4*1024);
            mbInit(settingsPtr);
        }
        public enum mbJsType
        {
            kMbJsTypeNumber = 0,
            kMbJsTypeString = 1,
            kMbJsTypeBool = 2,
            //kMbJsTypeObject = 3,
            //kMbJsTypeFunction = 4,
            kMbJsTypeUndefined = 5,
            //kMbJsTypeArray = 6,
            kMbJsTypeNull = 7,
        }
        public enum mbWindowType
        {
            MB_WINDOW_TYPE_POPUP,
            MB_WINDOW_TYPE_TRANSPARENT,
            MB_WINDOW_TYPE_CONTROL
        }
        public enum mbSettingMask
        {
            MB_SETTING_PROXY = 1,
            MB_ENABLE_NODEJS = 1 << 3,
            MB_ENABLE_DISABLE_H5VIDEO = 1 << 4,
            MB_ENABLE_DISABLE_PDFVIEW = 1 << 5,
            MB_ENABLE_DISABLE_CC = 1 << 6,
            MB_ENABLE_ENABLE_EGLGLES2 = 1 << 7, // 测试功能，请勿使用
            MB_ENABLE_ENABLE_SWIFTSHAER = 1 << 8, // 测试功能，请勿使用
        }
        public enum mbProxyType
        {
            MB_PROXY_NONE,
            MB_PROXY_HTTP,
            MB_PROXY_SOCKS4,
            MB_PROXY_SOCKS4A,
            MB_PROXY_SOCKS5,
            MB_PROXY_SOCKS5HOSTNAME
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct mbSettings
        {
            public mbProxy proxy;
            public uint mask; // 208 offset
            public IntPtr blinkThreadInitCallback;
            public IntPtr blinkThreadInitCallbackParam;
            public IntPtr version;
            public IntPtr mainDllPath;
            public IntPtr mainDllHandle;
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct mbProxy
        {
            public mbProxyType type;
            [MarshalAs(UnmanagedType.ByValArray,SizeConst =100,ArraySubType =UnmanagedType.U1)]
            public char[] hostname;
            public ushort port;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.U1)]
            public char[] username;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.U1)]
            public char[] password;
        }
    ;
        [StructLayout(LayoutKind.Sequential)]
        internal struct mbRect
        {
            public int x;
            public int y;
            public int w;
            public int h;
        }
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        internal delegate void mbTitleChangedCallback(IntPtr webView, IntPtr param, [MarshalAs(UnmanagedType.LPUTF8Str)]string title);
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        internal delegate void mbPaintUpdatedCallback(IntPtr webView, IntPtr param, IntPtr hdc, int x, int y, int cx, int cy);
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        internal delegate void mbPaintBitUpdatedCallback(IntPtr webView, IntPtr param, IntPtr buffer, ref MBVip.mbRect rect, int width, int height);
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        [return:MarshalAs(UnmanagedType.Bool)]
        internal delegate bool mbLoadUrlBeginCallback(IntPtr webView, IntPtr param, [MarshalAs(UnmanagedType.LPUTF8Str)]string url, IntPtr job);
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        internal delegate void mbLoadUrlEndCallback(IntPtr webView, IntPtr param, [MarshalAs(UnmanagedType.LPUTF8Str)]string url, IntPtr job, IntPtr buf, int len);
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        internal delegate void mbRunJsCallback(IntPtr webView, IntPtr param, IntPtr es, Int64 v);
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        internal delegate void mbJsQueryCallback(IntPtr webView, IntPtr param, IntPtr es, Int64 queryId, int customMsg, [MarshalAs(UnmanagedType.LPUTF8Str)] string request);
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        internal delegate void mbDocumentReadyCallback(IntPtr webView, IntPtr param, IntPtr frameId);


        const string node_dll_name = "mb";
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern void mbInit(IntPtr settings);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr mbCreateInitSettings();
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr mbSetInitSettings(IntPtr settings, string name, string value);
        [DllImport(node_dll_name,CallingConvention =CallingConvention.StdCall)]
        public static extern IntPtr mbCreateWebView();
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr mbCreateWebWindow(mbWindowType type,IntPtr parent,int x,int y,int width,int height);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern void mbSetAutoDrawToHwnd(IntPtr webView, [MarshalAs(UnmanagedType.Bool)] bool toHwnd);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern void mbSetTransparent(IntPtr mbWebView,[MarshalAs(UnmanagedType.Bool)]bool transparent);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        public static extern void mbLoadURL(IntPtr mbWebView, [MarshalAs(UnmanagedType.LPUTF8Str)]string url);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern void mbOnPaintUpdated(IntPtr webView, mbPaintUpdatedCallback callback, IntPtr callbackParam);
        [DllImport(node_dll_name,CallingConvention =CallingConvention.StdCall)]
        public static extern void mbOnPaintBitUpdated(IntPtr webView, mbPaintBitUpdatedCallback callback, IntPtr callbackParam);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern void mbResize(IntPtr webView, int w, int h);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern void mbOnLoadUrlBegin(IntPtr webView, mbLoadUrlBeginCallback callback, IntPtr callbackParam);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern void mbSetHandle(IntPtr webView, IntPtr wnd);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern void mbSetHandleOffset(IntPtr webView, int x,int y);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool mbFireKeyDownEvent(IntPtr webView, uint virtualKeyCode, uint flags, bool systemKey);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool mbFireKeyUpEvent(IntPtr webView, uint virtualKeyCode, uint flags, bool systemKey);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern void mbSetFocus(IntPtr webView);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public static extern void mbKillFocus(IntPtr webView);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool mbFireWindowsMessage(IntPtr webView, IntPtr hWnd, uint message, uint wParam, uint lParam, out int result);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool mbFireKeyPressEvent(IntPtr webView, uint virtualKeyCode, uint flags, bool systemKey);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool mbFireMouseWheelEvent(IntPtr webView, int x, int y, int delta, uint flags);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool mbFireMouseEvent(IntPtr webView, uint message, int x, int y, uint flags);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        public static extern void mbRunJs(IntPtr webView, IntPtr frameId, [MarshalAs(UnmanagedType.LPUTF8Str)] string script, [MarshalAs(UnmanagedType.Bool)] bool isInClosure, mbRunJsCallback callback, IntPtr param, IntPtr unuse);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        public static extern Int64 mbRunJsSync(IntPtr webView, IntPtr frameId, [MarshalAs(UnmanagedType.LPUTF8Str)] string script, [MarshalAs(UnmanagedType.Bool)] bool isInClosure);        
        [DllImport(node_dll_name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public static extern double mbJsToDouble(IntPtr es, Int64 v);
        [DllImport(node_dll_name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        [return:MarshalAs(UnmanagedType.Bool)]
        public static extern bool mbJsToBoolean(IntPtr es, Int64 v);
        [DllImport(node_dll_name,CharSet =CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr mbJsToString(IntPtr es, Int64 v);
        [DllImport(node_dll_name, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public static extern mbJsType mbGetJsValueType(IntPtr es, Int64 v);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public extern static void mbDestroyWebView(IntPtr webView);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public extern static void mbNetHookRequest(IntPtr jobPtr);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public extern static void mbOnLoadUrlEnd(IntPtr webView, mbLoadUrlEndCallback callback, IntPtr callbackParam);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public extern static void mbNetSetData(IntPtr jobPtr, IntPtr buf, int len);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public extern static void mbOnJsQuery(IntPtr webView, mbJsQueryCallback callback, IntPtr param);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public extern static void mbResponseQuery(IntPtr webView, Int64 queryId, int customMsg, [MarshalAs(UnmanagedType.LPUTF8Str)] string response);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public extern static IntPtr mbWebFrameGetMainFrame(IntPtr webView);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public extern static void mbSetDebugConfig(IntPtr webView, string debugString, string param);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public extern static void mbOnTitleChanged(IntPtr webView, mbTitleChangedCallback callback, IntPtr callbackParam);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall)]
        public extern static void mbSetResourceGc(IntPtr webView, int intervalSec);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        public extern static int mbGetCursorInfoType(IntPtr webView);
        [DllImport(node_dll_name, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        public extern static void mbOnDocumentReady(IntPtr webView, mbDocumentReadyCallback callback, IntPtr param);
    }
}
